#ifndef ODBC_BASIC_STATEMENT_HPP
#define ODBC_BASIC_STATEMENT_HPP

#include "odbc/connection_concept.hpp"
#include "odbc/stat_exec_policy_concept.hpp"
#include "odbc/parameter.hpp"
#include "odbc/odbc_error.hpp"
#include "odbc/details/connection_visitor.hpp"
#include <boost/foreach.hpp>

namespace odbc
{

namespace details { template< class Stat> class statement_visitor; }

template< class StatExecPolicy>
class basic_statement
{
	BOOST_CONCEPT_ASSERT( (stat_exec_policy_concept< StatExecPolicy>));
	typedef parameter< StatExecPolicy> parameter_type;
	typedef std::list< parameter_type*> param_collection;
public:
	typedef StatExecPolicy execution_policy;

public:
	template< class Connection>
	basic_statement( const Connection& conn, const std::string& stat_str)
		: handle_( SQL_NULL_HANDLE), stat_string_( stat_str)
	{
		BOOST_CONCEPT_ASSERT( (connection_concept< Connection>));
		SQLHANDLE conn_h = details::connection_visitor< Connection>::get_handle( conn);
		throw_if_stat_failed( SQLAllocHandle( SQL_HANDLE_STMT, conn_h, &handle_), handle_);
		StatExecPolicy::prepare_statement( handle_, stat_string_);
	}

	~basic_statement()
	{
		BOOST_FOREACH( parameter_type* p, parameters_) { delete p; }
		SQLFreeStmt( handle_, SQL_CLOSE);
		SQLFreeHandle( SQL_HANDLE_STMT, handle_);
	}

	template< class T>
	void add_parameter( const T& value, typename parameter_type::param_direction direction = parameter_type::dir_in)
	{
		// TODO: Concept checking type T: it should be a supported database value
		parameter_type* new_param = new parameter_type( handle_, details::buffer< T>( value), parameters_.size() + 1, direction);
		parameters_.push_back( new_param);
	}

	void execute()
	{
		SQLCloseCursor( handle_);
		StatExecPolicy::execute_statement( handle_, stat_string_);
	}

private:
	SQLHANDLE handle_;
	std::string stat_string_;
	param_collection parameters_;

	template< class Stat> friend class details::statement_visitor;
};


} // namespace odbc

#endif // ODBC_BASIC_STATEMENT_HPP
